#include "mdxserver.h"
#include <QDebug>
#define MODNAME "MDxserver"

MDxserver::MDxserver(QObject *parent) :
    QObject(parent)
{
    this->server = new xmlrpc::Server(this);
    //this->server->registerMethod("logon",QVariant::String,QVariant::String,QVariant::String);
    // авторизация пользователя:
    // принимаем логин и пароль
    // отдаем уникальный хэшь строку
    // который и будет выступать в роли идентификатора
    this->server->registerMethod("logon", QVariant::List,
                                 QVariant::List );
    // запрос данных по пользователям.
    this->server->registerMethod("getuserslist",QVariant::List,
                                 QVariant::List);
    connect(this->server,SIGNAL(incomingRequest(int,QString,QList<xmlrpc::Variant>)),
            this,SLOT(slotProcessRequest(int,QString,QList<xmlrpc::Variant>)));

    // set defaults
    this->port=9988;
    this->session_ttl=3600;
}

void MDxserver::setPort(int port){
    this->port = port;
}

QString MDxserver::sqlsafe(const QString & str){
    QString aa = str;
    aa.replace("\\","\\\\");
    aa.replace("\"","\\\"");
    aa.replace("'","\\'");
    return aa;
}

void MDxserver::setBase(const QString &addr, const QString &user, const QString &pass, const QString &dbname, int port){
    this->db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName(addr);
    db.setPort(port);
    db.setDatabaseName(dbname);
    db.setUserName(user);
    db.setPassword(pass);

}

void MDxserver::start(){
    if(!db.open()){
        emit this->sigLog(MODNAME,1,"Failure connect to database, error text is:\n"+db.lastError().text());
        exit(1);
    }else{
        emit this->sigLog(MODNAME,2,QString("connect to database success"));
    if(this->server->listen(this->port)){
        emit this->sigLog(MODNAME,2,QString("xml-rpc server started on port %1").arg(this->port));
    }else{
        emit this->sigLog(MODNAME,2,QString("failure start xml-rpc on port %1").arg(this->port));
        exit(2);
    }
    }
}


void MDxserver::slotProcessRequest(int id, QString methodName, QList<xmlrpc::Variant> parameters){
    // перечень методов

    // logon - метод авторизации пользователя
    if(methodName == "logon"){
        emit this->sigLog(MODNAME,2,QString("start method  - logon"));
        // проверяем количество параметров
        if(parameters.at(0).toList().size()!=2){
            // неверное количество параметров
            emit this->sigLog(MODNAME,1,QString("error ")+ERR_PARAMSCOUNT);
            this->server->sendFault(id,ERR_PARAMSCOUNT_ID,ERR_PARAMSCOUNT);
        }else{
            // все гуд, стучимся в базу и проверяем есть ли такой юзер с паролем
            //select count(*) from `users` where `username`='user' and `password`=md5('user');
            QString qline=QString("select count(*) from `users` where `username`='%1' and `password`=md5('%2')")
                    .arg(this->sqlsafe(parameters.at(0).toList().at(0).toString()))
                    .arg(this->sqlsafe(parameters.at(0).toList().at(1).toString()));
            QSqlQuery query;
            emit this->sigLog(MODNAME,3,QString("debug sql - ")+qline);
            if(!query.exec(qline)){
                emit this->sigLog(MODNAME,1,QString("error ")+ERR_SQLERR);
                this->server->sendFault(id,ERR_SQLERR_ID,ERR_SQLERR);
            }else{
            query.next();
            int isuser = query.value(0).toInt();
            if(isuser!=1){
                // юзверь не существует или задублирован. фейл кароче гг
                emit this->sigLog(MODNAME,1,QString("error ")+ERR_LOGON);
                this->server->sendFault(id,ERR_LOGON_ID,ERR_LOGON);
            }else{
                // все отлично
                // генерируем уникальный хэш
                QString unicHash = QString::number(QDate::currentDate().toJulianDay())+"_"
                        +QString(QTime::currentTime().toString())+"_"
                        +QString::number(QTime::currentTime().msec());
                emit this->sigLog(MODNAME,3,QString("logon user %1 is ok. hash is %2")
                                  .arg(this->sqlsafe(parameters.at(0).toList().at(0).toString()))
                                  .arg(unicHash));
                emit this->sigLog(MODNAME,3,QString("Update sessions"));
                // а теперь создаем сессию для этого пользователя и уникального хэша.
                QString qline = QString
                        ("insert into `sessions` (`id_users`,`lastsync`,`userhash`) values((select `id` from `users` where `username`='%1'),NOW(),'%2')")
                        .arg(parameters.at(0).toList().at(0).toString())
                        .arg(unicHash);
                QSqlQuery query;
                emit this->sigLog(MODNAME,3,QString("debug sql - ")+qline);
                if(!query.exec(qline)){
                    emit this->sigLog(MODNAME,1,QString("error ")+ERR_SQLERR);
                    this->server->sendFault(id,ERR_SQLERR_ID,ERR_SQLERR);
                }else{
                // хешь создался. отдаем его клиенту.
                    QList<xmlrpc::Variant> ret;
                    ret.append(unicHash);
                // получаем тип пользователя
                    QString qx = QString("select `usertype` from `users` where `username`='%1'")
                            .arg(this->sqlsafe(parameters.at(0).toList().at(0).toString()));
                    emit this->sigLog(MODNAME,3,QString("debug sql - ")+qx);
                    QSqlQuery qq;
                    if(!qq.exec(qx)){
                        emit this->sigLog(MODNAME,1,QString("error ")+ERR_SQLERR);
                        this->server->sendFault(id,ERR_SQLERR_ID,ERR_SQLERR);
                    }
                    // добавляем то что вернулось. это тип
                    qq.next();
                    ret.append(qq.value(0).toInt());
                    this->server->sendReturnValue(id,ret);
                }
            }
            }
        }
    }
    // прилетел запрос на список пользователей.
    if(methodName == "getuserslist"){
        emit this->sigLog(MODNAME,2,QString("start method  - getuserslist"));
        // опапа прилетел запрос
        // сначала зачищаем сессии
        if(!this->clearOldSessions()){
                emit this->sigLog(MODNAME,1,QString("error ")+ERR_SESSCLRERR);
                this->server->sendFault(id,ERR_SESSCLRERR_ID,ERR_SESSCLRERR);
        }else{

        // проверяем количество параметров - должно быть 2 имя пользователя и его хэш
        if(parameters.at(0).toList().size()!=2){
            // неверное количество параметров
            emit this->sigLog(MODNAME,1,QString("error ")+ERR_PARAMSCOUNT);
            this->server->sendFault(id,ERR_PARAMSCOUNT_ID,ERR_PARAMSCOUNT);
        }else{
            // теперь проверяем наличие сессии данного пользователя в списке активных,
            // ежели нема ее там то кишь его кишь из работы, пущай перелогиниться.


        }
        }
    }

}

void MDxserver::setSessionTtl(int sec){
    this->session_ttl=sec;
}

bool MDxserver::clearOldSessions(){
    // основная задача удалить старые сессии
    //
    QSqlQuery qq;
    QString qline=QString("delete from `sessions` where `lastsync`<now() - INTERVAL %1 SECOND ").arg(this->session_ttl);
    emit this->sigLog(MODNAME,3,QString("debug sql - ")+qline);
    if(!qq.exec(qline)){
        return false;
    }
        return true;
}
